#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "StringFilter.h"
#include "CType.h"
#include "ET_stdio.h"

//---- StringFilter ------------------------------------------------------------

StringFilter::StringFilter() : StreamBuf()
{
	closed= FALSE;
}

//---- StringEncoder -----------------------------------------------------------

StringEncoder::StringEncoder() : StringFilter()
{
	col= 0;
}

int StringEncoder::Overflow(u_char *bp, int n)
{
	register u_char c, *p= bp;

	while (n-- > 0) {
		switch(c= *p++) {
		case '{':
		case '}':
			sb->sputc('\\'); sb->sputc('x');
			sb->sputc(hexChars[c / 16]);
			sb->sputc(hexChars[c & 0x0f]);
			col+= 4;
			break;
		case '\n':
			sb->sputc('\\'); sb->sputc('n'); col+= 2;
			break;
		case '\r':
			sb->sputc('\\'); sb->sputc('r'); col+= 2;
			break;
		case '\t':
			sb->sputc('\\'); sb->sputc('t'); col+= 2;
			break;
		case '\v':
			sb->sputc('\\'); sb->sputc('v'); col+= 2;
			break;
		case '\f':
			sb->sputc('\\'); sb->sputc('f'); col+= 2;
			break;
		case '\b':
			sb->sputc('\\'); sb->sputc('b'); col+= 2;
			break;
		case '\"':
			sb->sputc('\\'); sb->sputc('\"'); col+= 2;
			break;
		case '\'':
			sb->sputc('\\'); sb->sputc('\''); col+= 2;
			break;
		case '\\':
			sb->sputc('\\'); sb->sputc('\\'); col+= 2;
			break;
		default:
			if (Isascii(c) && Isprint(c)) {
				sb->sputc(c); col++;
			} else {
				sb->sputc('\\'); sb->sputc('x');
				sb->sputc(hexChars[c / 16]);
				sb->sputc(hexChars[c & 0x0f]);
				col+= 4;
			}
		}
		if (col >= 72) {
			sb->sputc('\n');
			col= 0;
		}
	}
	return p-bp;
}

void StringEncoder::Close()
{
	if (!closed) {
		sb->sputc('\"');
		closed= TRUE;
	}
}

//---- StringDecoder -----------------------------------------------------------

StringDecoder::StringDecoder() : StringFilter()
{
	eof= 0;
}

int StringDecoder::Underflow(u_char *bp, int n)
{
	int c, k, j;
	register u_char *p= bp;

	if (eof)
		return EOF;

	while (--n >= 0) {
		if ((c= sb->sgetc()) == EOF) {
			eof= TRUE;
			break;
		}
		sb->stossc();
		switch (c) {
		case '\"':
			eof= TRUE;
			return p-bp;
		case '\\':
			c= sb->sgetc();
			sb->stossc();
			switch (c) {
			case EOF:
				eof= TRUE;
				return p-bp;
			case 'n':
				*p++= '\n';
				continue;
			case 'r':
				*p++= '\r';
				continue;
			case 'b':
				*p++= '\b';
				continue;
			case 'f':
				*p++= '\f';
				continue;
			case 't':
				*p++= '\t';
				continue;
			case 'v':
				*p++= '\v';
				continue;
			case 'x':
				for (k= j= 0; j < 2 && k < 256; j++) {
					c= sb->sgetc();
					if (! Isxdigit(c))
						break;
					sb->stossc();
					k= k*16 + HexValue(c);
				}
				*p++= k;
				continue;

			default:
				*p++= c;
				continue;
			}
			break;

		default:
			if (Isprint(c))
				*p++= c;
			continue;
		}
	}
	return p-bp;
}

